package com.ruoyi.project.system.service.impl

import com.ruoyi.common.constant.*
import com.ruoyi.common.utils.*
import com.ruoyi.framework.web.domain.TreeSelect
import com.ruoyi.project.system.domain.SysMenu
import com.ruoyi.project.system.domain.SysUser
import com.ruoyi.project.system.domain.vo.MetaVo
import com.ruoyi.project.system.domain.vo.RouterVo
import com.ruoyi.project.system.mapper.SysMenuMapper
import com.ruoyi.project.system.mapper.SysRoleMapper
import com.ruoyi.project.system.mapper.SysRoleMenuMapper
import com.ruoyi.project.system.service.ISysMenuService
import org.apache.commons.lang3.StringUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.*
import java.util.stream.Collectors

/**
 * 菜单 业务层处理
 *
 * @author ruoyi
 */
@Service
class SysMenuServiceImpl : ISysMenuService {
    @Autowired
    private val menuMapper: SysMenuMapper? = null

    @Autowired
    private val roleMapper: SysRoleMapper? = null

    @Autowired
    private val roleMenuMapper: SysRoleMenuMapper? = null

    /**
     * 根据用户查询系统菜单列表
     *
     * @param userId 用户ID
     * @return 菜单列表
     */
    override fun selectMenuList(userId: Long?): List<SysMenu>? {
        return selectMenuList(SysMenu(), userId)
    }

    /**
     * 查询系统菜单列表
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    override fun selectMenuList(menu: SysMenu?, userId: Long?): List<SysMenu>? {
        // 管理员显示所有菜单信息
        val menuList: List<SysMenu>? = if (SysUser.isAdmin(userId)) {
            menuMapper!!.selectMenuList(menu)
        } else {
            menu!!.params?.set("userId", userId!!)
            menuMapper!!.selectMenuListByUserId(menu)
        }
        return menuList
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    override fun selectMenuPermsByUserId(userId: Long): Set<String> {
        val perms = menuMapper!!.selectMenuPermsByUserId(userId)
        val permsSet: MutableSet<String> = HashSet()
        perms!!
            .asSequence()
            .filter { StringUtils.isNotEmpty(it) }
            .forEach { perm ->
                permsSet.addAll(listOf(*perm.trim { it <= ' ' }
                    .split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()))
            }
        return permsSet
    }

    /**
     * 根据角色ID查询权限
     *
     * @param roleId 角色ID
     * @return 权限列表
     */
    override fun selectMenuPermsByRoleId(roleId: Long?): Set<String> {
        val perms = menuMapper!!.selectMenuPermsByRoleId(roleId)
        val permsSet: MutableSet<String> = HashSet()
        for (perm in perms!!) {
            if (StringUtils.isNotEmpty(perm)) {
                permsSet.addAll(listOf(*perm!!.trim { it <= ' ' }
                    .split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()))
            }
        }
        return permsSet
    }

    /**
     * 根据用户ID查询菜单
     *
     * @param userId 用户名称
     * @return 菜单列表
     */
    override fun selectMenuTreeByUserId(userId: Long?): List<SysMenu> {
        val menus: List<SysMenu>? = if (SecurityUtils.isAdmin(userId)) {
            menuMapper!!.selectMenuTreeAll()
        } else {
            menuMapper!!.selectMenuTreeByUserId(userId)
        }
        return getChildPerms(menus, 0)
    }

    /**
     * 根据角色ID查询菜单树信息
     *
     * @param roleId 角色ID
     * @return 选中菜单列表
     */
    override fun selectMenuListByRoleId(roleId: Long?): List<Long?>? {
        val role = roleMapper!!.selectRoleById(roleId)
        return menuMapper!!.selectMenuListByRoleId(roleId, role!!.isMenuCheckStrictly)
    }

    /**
     * 构建前端路由所需要的菜单
     *
     * @param menus 菜单列表
     * @return 路由列表
     */
    override fun buildMenus(menus: List<SysMenu>): List<RouterVo> {
        val routers: MutableList<RouterVo> = LinkedList()
        menus.forEach { menu ->
            val router = RouterVo()
            router.hidden = "1" == menu.visible
            router.name = getRouteName(menu)
            router.path = getRouterPath(menu)
            router.component = getComponent(menu)
            router.query = menu.query
            router.meta = MetaVo(menu.menuName, menu.icon, StringUtils.equals("1", menu.isCache), menu.path)
            val cMenus = menu.children
            when {
                cMenus.isNotEmpty() && UserConstants.TYPE_DIR == menu.menuType -> {
                    router.alwaysShow = true
                    router.redirect = "noRedirect"
                    router.children = buildMenus(cMenus)
                }

                isMenuFrame(menu) -> {
                    router.meta = null
                    val childrenList: MutableList<RouterVo> = ArrayList()
                    val children = RouterVo()
                    children.path = menu.path
                    children.component = menu.component
                    children.name = StringUtils.capitalize(menu.path)
                    children.meta = MetaVo(menu.menuName, menu.icon, StringUtils.equals("1", menu.isCache), menu.path)
                    children.query = menu.query
                    childrenList.add(children)
                    router.children = childrenList
                }

                menu.parentId!!.toInt() == 0 && isInnerLink(menu) -> {
                    router.meta = MetaVo(menu.menuName, menu.icon)
                    router.path = "/"
                    val childrenList: MutableList<RouterVo> = ArrayList()
                    val children = RouterVo()
                    val routerPath = innerLinkReplaceEach(menu.path)
                    children.path = routerPath
                    children.component = UserConstants.INNER_LINK
                    children.name = StringUtils.capitalize(routerPath)
                    children.meta = MetaVo(menu.menuName, menu.icon, menu.path)
                    childrenList.add(children)
                    router.children = childrenList
                }
            }
            routers.add(router)
        }
        return routers
    }

    /**
     * 构建前端所需要树结构
     *
     * @param menus 菜单列表
     * @return 树结构列表
     */
    override fun buildMenuTree(menus: MutableList<SysMenu>): List<SysMenu> {
        var returnList: MutableList<SysMenu> = ArrayList()
        val tempList: MutableList<Long> = ArrayList()
        for (dept in menus) {
            tempList.add(dept.menuId!!)
        }
        val iterator: Iterator<SysMenu> = menus.iterator()
        while (iterator.hasNext()) {
            val menu = iterator.next()
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(menu.parentId)) {
                recursionFn(menus, menu)
                returnList.add(menu)
            }
        }
        if (returnList.isEmpty()) {
            returnList = menus
        }
        return returnList
    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param menus 菜单列表
     * @return 下拉树结构列表
     */
    override fun buildMenuTreeSelect(menus: List<SysMenu>?): List<TreeSelect> {
        val menuTrees = buildMenuTree(menus!!.toMutableList())
        return menuTrees.stream().map { menu: SysMenu? -> TreeSelect(menu!!) }.collect(Collectors.toList())
    }

    /**
     * 根据菜单ID查询信息
     *
     * @param menuId 菜单ID
     * @return 菜单信息
     */
    override fun selectMenuById(menuId: Long?): SysMenu? {
        return menuMapper!!.selectMenuById(menuId)
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    override fun hasChildByMenuId(menuId: Long?): Boolean {
        val result = menuMapper!!.hasChildByMenuId(menuId)
        return result > 0
    }

    /**
     * 查询菜单使用数量
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    override fun checkMenuExistRole(menuId: Long?): Boolean {
        val result = roleMenuMapper!!.checkMenuExistRole(menuId)
        return result > 0
    }

    /**
     * 新增保存菜单信息
     *
     * @param menu 菜单信息
     * @return 结果
     */
    override fun insertMenu(menu: SysMenu?): Int {
        return menuMapper!!.insertMenu(menu)
    }

    /**
     * 修改保存菜单信息
     *
     * @param menu 菜单信息
     * @return 结果
     */
    override fun updateMenu(menu: SysMenu?): Int {
        return menuMapper!!.updateMenu(menu)
    }

    /**
     * 删除菜单管理信息
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    override fun deleteMenuById(menuId: Long?): Int {
        return menuMapper!!.deleteMenuById(menuId)
    }

    /**
     * 校验菜单名称是否唯一
     *
     * @param menu 菜单信息
     * @return 结果
     */
    override fun checkMenuNameUnique(menu: SysMenu): String {
        val menuId = if (com.ruoyi.common.utils.StringUtils.isNull(menu.menuId)) -1L else menu.menuId
        val info = menuMapper!!.checkMenuNameUnique(menu.menuName, menu.parentId)
        return if (com.ruoyi.common.utils.StringUtils.isNotNull(info) && info!!.menuId!!.toLong() != menuId!!.toLong()) {
            UserConstants.NOT_UNIQUE
        } else UserConstants.UNIQUE
    }

    /**
     * 获取路由名称
     *
     * @param menu 菜单信息
     * @return 路由名称
     */
    fun getRouteName(menu: SysMenu): String {
        var routerName = StringUtils.capitalize(menu.path)
        // 非外链并且是一级目录（类型为目录）
        if (isMenuFrame(menu)) {
            routerName = StringUtils.EMPTY
        }
        return routerName
    }

    /**
     * 获取路由地址
     *
     * @param menu 菜单信息
     * @return 路由地址
     */
    fun getRouterPath(menu: SysMenu): String? {
        var routerPath = menu.path
        // 内链打开外网方式
        if (menu.parentId!!.toInt() != 0 && isInnerLink(menu)) {
            routerPath = innerLinkReplaceEach(routerPath)
        }
        // 非外链并且是一级目录（类型为目录）
        if (0 == menu.parentId!!.toInt() && UserConstants.TYPE_DIR == menu.menuType && UserConstants.NO_FRAME == menu.isFrame) {
            routerPath = "/" + menu.path
        } else if (isMenuFrame(menu)) {
            routerPath = "/"
        }
        return routerPath
    }

    /**
     * 获取组件信息
     *
     * @param menu 菜单信息
     * @return 组件信息
     */
    fun getComponent(menu: SysMenu): String {
        var component = UserConstants.LAYOUT
        if (com.ruoyi.common.utils.StringUtils.isNotEmpty(menu.component) && !isMenuFrame(menu)) {
            component = menu.component!!
        } else if (com.ruoyi.common.utils.StringUtils.isEmpty(menu.component) && menu.parentId!!.toInt() != 0 && isInnerLink(
                menu
            )
        ) {
            component = UserConstants.INNER_LINK
        } else if (com.ruoyi.common.utils.StringUtils.isEmpty(menu.component) && isParentView(menu)) {
            component = UserConstants.PARENT_VIEW
        }
        return component
    }

    /**
     * 是否为菜单内部跳转
     *
     * @param menu 菜单信息
     * @return 结果
     */
    fun isMenuFrame(menu: SysMenu): Boolean {
        return menu.parentId!!.toInt() == 0 && UserConstants.TYPE_MENU == menu.menuType && menu.isFrame == UserConstants.NO_FRAME
    }

    /**
     * 是否为parent_view组件
     *
     * @param menu 菜单信息
     * @return 结果
     */
    fun isParentView(menu: SysMenu): Boolean {
        return menu.parentId!!.toInt() != 0 && UserConstants.TYPE_DIR == menu.menuType
    }

    /**
     * 是否为内链组件
     *
     * @param menu 菜单信息
     * @return 结果
     */
    fun isInnerLink(menu: SysMenu): Boolean {
        return menu.isFrame == UserConstants.NO_FRAME && com.ruoyi.common.utils.StringUtils.ishttp(menu.path)
    }

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list 分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    fun getChildPerms(list: List<SysMenu>?, parentId: Int): List<SysMenu> {
        val returnList: MutableList<SysMenu> = ArrayList()
        val iterator = list!!.iterator()
        while (iterator.hasNext()) {
            val t = iterator.next()
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.parentId == parentId.toLong()) {
                recursionFn(list, t)
                returnList.add(t)
            }
        }
        return returnList
    }

    /**
     * 递归列表
     *
     * @param list
     * @param t
     */
    private fun recursionFn(list: List<SysMenu>?, t: SysMenu) {
        // 得到子节点列表
        val childList = getChildList(list, t)
        t.children = childList
        for (tChild in childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild)
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private fun getChildList(list: List<SysMenu>?, t: SysMenu): List<SysMenu> {
        val tlist: MutableList<SysMenu> = ArrayList()
        val it = list!!.iterator()
        while (it.hasNext()) {
            val n = it.next()
            if (n.parentId!!.toLong() == t.menuId!!.toLong()) {
                tlist.add(n)
            }
        }
        return tlist
    }

    /**
     * 判断是否有子节点
     */
    private fun hasChild(list: List<SysMenu>?, t: SysMenu): Boolean {
        return getChildList(list, t).isNotEmpty()
    }

    /**
     * 内链域名特殊字符替换
     *
     * @return
     */
    fun innerLinkReplaceEach(path: String?): String {
        return StringUtils.replaceEach(path, arrayOf(Constants.HTTP, Constants.HTTPS), arrayOf("", ""))
    }

    companion object {
        const val PREMISSION_STRING = "perms[\"{0}\"]"
    }
}
